using System;
using System.Collections;
using System.Collections.Generic;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;

namespace FireStarterModeller.Logic
{
    public class FMDefClassFactory : IDefClassFactory
    {
        private IDMSolution _solution;
        protected IDMSolution Solution
        {
            get { return _solution ?? (_solution = new SolutionCreator().CreateSolution()); }
            private set { _solution = value; }
        }

        private DMClass _dmClass;
        public FMDefClassFactory(IDMSolution solution) { Solution = solution; }
        public FMDefClassFactory():this(null) {}

        public ClassDefCol CreateClassDefCol() { return new ClassDefCol(); }


        public IClassDef CreateClassDef(string assemblyName, string className, string displayName, IPrimaryKeyDef primaryKeyDef, 
            IPropDefCol propDefCol, KeyDefCol keyDefCol, 
            IRelationshipDefCol relationshipDefCol, UIDefCol uiDefCol)
        {
            _dmClass = new DMClass();
            _dmClass.ClassNameBO = className;
            _dmClass.DisplayName = displayName;
            DMAssembly assembly = Solution.Assemblies.Find(dmAssembly => dmAssembly.AssemblyName == assemblyName);
            if (assembly == null)
            {
                assembly = Solution.Assemblies.CreateBusinessObject();
                assembly.AssemblyName = assemblyName;
            }
            _dmClass.Assembly = assembly;

            if (propDefCol != null)
            {
                foreach (IPropDef propDef in propDefCol)
                {
                    _dmClass.Properties.Add((DMProperty)propDef);
                }
            }
            if (primaryKeyDef != null)
            {
                _dmClass.ObjectIdentity = (DMObjectIdentity)primaryKeyDef;
            }
            if (keyDefCol != null)
            {
                foreach (IKeyDef keyDef in keyDefCol)
                {
                    _dmClass.UniqueConstraints.Add((DMUniqueConstraint)keyDef);
                }
            }
            var classDef = ((IClassDef)_dmClass);
            classDef.RelationshipDefCol = relationshipDefCol;
            classDef.UIDefCol = uiDefCol;
            return _dmClass;
        }

        public UIDefCol CreateUIDefCol() { return new UIDefCol(); }

        public IUIDef CreateUIDef(string name, IUIForm uiForm, IUIGrid uiGrid)
        {
            IUIDef uiDef = new UIView();
            uiDef.Name = name;
            uiDef.UIForm = uiForm;
            uiDef.UIGrid = uiGrid;
            return uiDef;
        }

        public IUIGrid CreateUIGridDef()
        {
            return new UIGridInfo();
        }

        public IUIGridColumn CreateUIGridProperty(string heading, string propertyName, string gridControlTypeName, string gridControlAssembly, bool editable, int width, PropAlignment alignment, Hashtable propertyAttributes)
        {
            IUIGridColumn uiGridColumn = new UIGridColumnInfo();
            uiGridColumn.Heading = heading;
            uiGridColumn.PropertyName = propertyName;
            uiGridColumn.Editable = editable;
            uiGridColumn.Width = width;
            uiGridColumn.Alignment = alignment;
            UIGridColumnInfo columnInfo = (UIGridColumnInfo) uiGridColumn;
            if (!string.IsNullOrEmpty(gridControlTypeName))
            {
                columnInfo.UIGridColumnControlType = UIGridColumnControlType.FindOrCreate((DMSolution) Solution, gridControlAssembly, gridControlTypeName);
            }

            foreach (DictionaryEntry dictionaryEntry in propertyAttributes)
            {
                columnInfo.UIParameters.Add(new UIParameter { Name = (string)dictionaryEntry.Key, Value = (string)dictionaryEntry.Value });
            }

            return uiGridColumn;
        }


        public IUIForm CreateUIFormDef() { return new UIFormInfo(); }

        public IUIFormTab CreateUIFormTab() { return new UITab(); }

        public IUIFormColumn CreateUIFormColumn() { return new UIColumnLayout(); }

        public ISuperClassDef CreateSuperClassDef(string assemblyName, string className, ORMapping orMapping, string id, string discriminator)
        {
            ISuperClassDef superClassDef = new DMInheritanceRelationship();
            superClassDef.ClassName = className;
            superClassDef.AssemblyName = assemblyName;
            superClassDef.ORMapping = orMapping;
            superClassDef.ID = id;
            superClassDef.Discriminator = discriminator;
            return superClassDef;
        }

        public IRelationshipDef CreateMultipleRelationshipDef(string relationshipName, string relatedAssemblyName, string relatedClassName, IRelKeyDef relKeyDef, bool keepReferenceToRelatedObject, string orderBy, DeleteParentAction deleteParentAction, InsertParentAction insertParentAction, RelationshipType relationshipType, int timeout)
        {
            const Cardinality cardinality = Cardinality.Multiple;
            DMRelationship relationship = CreateRelationship(cardinality, relationshipName, relatedClassName, relatedAssemblyName, relKeyDef, deleteParentAction, insertParentAction, relationshipType);

            relationship.DMSortOrder = DMSortOrder.FromString(orderBy);
            relationship.Timeout = timeout;
            return relationship;
        }

        private DMRelationship CreateRelationship(Cardinality cardinality, string relationshipName, string relatedClassName, string relatedAssemblyName, IRelKeyDef relKeyDef, DeleteParentAction deleteParentAction, InsertParentAction insertParentAction, RelationshipType relationshipType)
        {
            DMRelationship relationship = new DMRelationship(null);
            relationship.Cardinality = cardinality;
            relationship.RelationshipName = relationshipName;
            relationship.RelatedClassName = relatedClassName;
            relationship.ClassDM = _dmClass;
            relationship.RelatedAssemblyName = relatedAssemblyName;
            if (relKeyDef != null)
            {
                foreach (IRelPropDef relPropDef in relKeyDef)
                {
                    relationship.RelationshipProperties.Add((DMRelationshipProperty) relPropDef);
                }
            }
            relationship.DeleteAction = deleteParentAction;
            relationship.InsertParentAction = insertParentAction;
            relationship.RelationshipType = relationshipType;
            return relationship;
        }

        public virtual IRelationshipDef CreateSingleRelationshipDef(string relationshipName, string relatedAssemblyName, string relatedClassName,
                                                            IRelKeyDef relKeyDef, bool keepReferenceToRelatedObject, DeleteParentAction deleteParentAction, InsertParentAction insertParentAction, RelationshipType relationshipType)
        {
            const Cardinality cardinality = Cardinality.Single;
            DMRelationship relationship = CreateRelationship(cardinality, relationshipName, relatedClassName, relatedAssemblyName, relKeyDef, deleteParentAction, insertParentAction, relationshipType);
            return relationship;
        }

        public IRelationshipDefCol CreateRelationshipDefCol()
        {
            return new DMRelationshipCollection();
        }


        public IRelKeyDef CreateRelKeyDef()
        {
            return new DMRelationshipPropertyCollection();
        }

        public IRelPropDef CreateRelPropDef(string propDefName, string relPropName)
        {
            DMRelationshipProperty relProp = new DMRelationshipProperty(null)
                             {
                                 OwnerPropertyName = propDefName,
                                 RelatedPropertyName = relPropName
                             };
            return relProp;
        }

        public KeyDefCol CreateKeyDefCol()
        {
            return new KeyDefCol();
        }

        public IPropDefCol CreatePropDefCol()
        {
            return new DMPropertyCollection();

        }
        public IFilterDef CreateFilterDef(IList<IFilterPropertyDef> filterPropertyDefs)
        {
            UIGridFilter gridFilter = new UIGridFilter();
            foreach (IFilterPropertyDef filterPropertyDef in filterPropertyDefs)
            {
                gridFilter.UIGridFilterProps.Add((UIGridFilterProp)filterPropertyDef);
            }
            return gridFilter;
        }

        public IFilterPropertyDef CreateFilterPropertyDef(string propertyName, string label, string filterType, string filterTypeAssembly, FilterClauseOperator filterClauseOperator, Dictionary<string, string> parameters)
        {
            UIGridFilterProp gridFilterProp = new UIGridFilterProp {PropertyName = propertyName, LabelText = label};
            UITypeDefinition filterControlType = Solution.GetUIFilterControlType(filterTypeAssembly, filterType);
            gridFilterProp.UIGridFilterType = filterControlType;
            gridFilterProp.FilterClauseOp = filterClauseOperator;
            foreach (KeyValuePair<string, string> keyValuePair in parameters)
            {
                gridFilterProp.UIParameters.Add(new UIParameter { Name = keyValuePair.Key, Value = keyValuePair.Value });
            }

            return gridFilterProp;
        }
        public IPropRule CreatePropRuleDecimal(string name, string message)
        {
            DMPropRule propRule = (DMPropRule)CreateDMPropRule(name, message, "PropRuleDecimal");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "min", Value = decimal.MinValue.ToString(), OrdinalPosition = 1});
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "max", Value = decimal.MaxValue.ToString(), OrdinalPosition = 2});
            return propRule;
        }
        public IPropRule CreatePropRuleDate(string name, string message)
        {
            DMPropRule propRule = (DMPropRule)CreateDMPropRule(name, message, "PropRuleDate");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "min", Value = DateTime.MinValue.ToString(), OrdinalPosition = 1 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "max", Value = DateTime.MaxValue.ToString(), OrdinalPosition = 2 });
            return propRule;
        }

        public IPropRule CreatePropRuleInteger(string name, string message)
        {
            DMPropRule propRule = (DMPropRule)CreateDMPropRule(name, message, "PropRuleInteger");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "min", Value = int.MinValue.ToString(), OrdinalPosition = 1 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "max", Value = int.MaxValue.ToString(), OrdinalPosition = 2 });
            return propRule;

        }

        public IPropRule CreatePropRuleString(string name, string message)
        {
            DMPropRule propRule = (DMPropRule) CreateDMPropRule(name, message, "PropRuleString");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "minLength", Value = "0", OrdinalPosition = 1 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "maxLength", Value = "-1", OrdinalPosition = 2 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "patternMatch", Value = "", OrdinalPosition = 3 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "patternMatchMessage", Value = "", OrdinalPosition = 4 });
            return propRule;
        }

        public IPropRule CreatePropRuleSingle(string name, string message)
        {
            DMPropRule propRule = (DMPropRule)CreateDMPropRule(name, message, "PropRuleSingle");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "min", Value = Single.MinValue.ToString(), OrdinalPosition = 1 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "max", Value = Single.MaxValue.ToString(), OrdinalPosition = 2 });
            return propRule;
        }
        public IPropRule CreatePropRuleDouble(string name, string message)
        {
            DMPropRule propRule = (DMPropRule)CreateDMPropRule(name, message, "PropRuleDouble");
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "min", Value = double.MinValue.ToString(), OrdinalPosition = 1 });
            propRule.PropRuleParameters.Add(new DMPropRuleParameter { KeyName = "max", Value = double.MaxValue.ToString(), OrdinalPosition = 2 });
            return propRule;
        }

        private IPropRule CreateDMPropRule(string name, string message, string propRuleType)
        {
            DMPropRule propRule = new DMPropRule();
            propRule.PropRuleName = name;
            propRule.Message = message;
            propRule.Assembly = "Habanero.BO";
            propRule.Class = propRuleType;
            return propRule;
        }

        public ILookupList CreateDatabaseLookupList(string sqlString, int timeout, string assemblyName, string className, bool limitToList)
        {
            DMLookupListDatabase lookupListDatabase = new DMLookupListDatabase();
            lookupListDatabase.Sql = sqlString;
            lookupListDatabase.TimeOut = timeout;
            lookupListDatabase.Assembly = assemblyName;
            lookupListDatabase.LookupClassName = className;
            lookupListDatabase.LimitToList = limitToList;
            return lookupListDatabase;
        }


        public ILookupList CreateBusinessObjectLookupList(string assemblyName, string className, string criteria, string sort, int timeout)
        {
            DMLookupListBusinessObject lookupList = new DMLookupListBusinessObject();
            lookupList.AssemblyName = assemblyName;
            lookupList.ClassName = className; // _solution.AllClasses.Find(dmClass => dmClass.ClassNameBO == className);
            lookupList.Criteria = criteria;
            if (!String.IsNullOrEmpty(sort))
                lookupList.DMSortOrder = DMSortOrder.FromString(sort);
            lookupList.Timeout = timeout;
            return lookupList;
        }

        public ILookupList CreateSimpleLookupList(Dictionary<string, string> displayValueDictionary)
        {
            DMLookupListSimple lookupListSimple = new DMLookupListSimple();
            foreach (KeyValuePair<string, string> keyValuePair in displayValueDictionary)
            {
                lookupListSimple.ListItems.Add(new DMListItem { Display = keyValuePair.Key, Value = keyValuePair.Value });
            }
            return lookupListSimple;
        }

        public IKeyDef CreateKeyDef(string keyName)
        {
            IKeyDef keyDef = new DMUniqueConstraint();
            keyDef.KeyName = keyName;
            return keyDef;
        }

        public IPrimaryKeyDef CreatePrimaryKeyDef()
        {
            return new DMObjectIdentity();
        }

        public IPropDef CreatePropDef(string propertyName, string assemblyName, string typeName,
                                      PropReadWriteRule readWriteRule, string databaseFieldName, string defaultValueString,
                                      bool compulsory, bool autoIncrementing, int length,
                                      string displayName, string description, bool keepValuePrivate)
        {
            DMProperty property = new DMProperty();
            property.PropertyName = propertyName;
            property.PropertyType = DMPropertyType.FindOrCreate((DMSolution) Solution, assemblyName, typeName);
            property.ReadWriteRule = readWriteRule;
            property.MappedDBColumnName = databaseFieldName;
            property.DefaultValue = defaultValueString;
            property.Compulsory = compulsory;
            property.AutoIncrementing = autoIncrementing;
            property.Length = length;
            property.DisplayName = displayName;
            property.Description = description;
            property.KeepValuePrivate = keepValuePrivate;
            return property;
        }

        public IUIFormField CreateUIFormProperty(string label, string propertyName, string controlTypeName, string controlAssembly, string mapperTypeName
                , string mapperAssembly, bool editable, bool? showAsCompulsory, string toolTipText, Hashtable propertyAttributes, LayoutStyle layout)
        {
            UIField field = new UIField {LabelText = label};
            if (!string.IsNullOrEmpty(mapperTypeName))
            {
                field.UIControlMapperType = UIControlMapperType.FindOrCreate((DMSolution) Solution, mapperAssembly, mapperTypeName);
            }
            if (!string.IsNullOrEmpty(controlTypeName))
            {
                field.UIControlType = UIControlType.FindOrCreate((DMSolution) Solution, controlAssembly, controlTypeName);
            }
            field.PropertyName = propertyName;
            field.Editable = editable;
            field.ShowAsCompulsory = showAsCompulsory;
            field.ToolTipText = toolTipText;
            field.Layout = Enum.GetName(typeof(LayoutStyle), layout);
            
            foreach (DictionaryEntry attribute in propertyAttributes)
            {
                UIParameter parameter = new UIParameter();
                parameter.Name = (string)attribute.Key;
                parameter.Value = (string)attribute.Value;
                field.UIParameters.Add(parameter);
            }

            return field;
        }

    }

}